package com.szsh.bigdata.open.utils

import java.text.{ParseException, SimpleDateFormat}
import java.util.{Calendar, Date}
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
import scala.collection.mutable.ArrayBuffer
import scala.math.abs

object DateUtil {

    /**
     * 获取dateString起days天数后的日期
     * @param dateString yyyyMMdd
     * @param days 天数
     * @param format 可选的参数, 日期格式
     * @return yyyyMMdd
     */
    def dateAfterDays(dateString: String, days: Int, format: String = "yyyyMMdd"): String = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setTime(date)
        calendar.add(Calendar.DAY_OF_YEAR, days)
        sdf.format(calendar.getTime)
    }

    /**
     * 获取dateString起days月数后的日期
     * @param dateString yyyyMM
     * @param months 月份数
     * @param format 可选的参数, 月份格式
     * @return yyyyMM
     */
    def dateAfterMonths(dateString: String, months: Int, format: String = "yyyyMM"): String = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setTime(date)
        calendar.add(Calendar.MONTH, months)
        sdf.format(calendar.getTime)
    }

    /**
     * 获取当前时间,精确到毫秒
     * @return yyyy-MM-dd HH:mm:ss SSS
     */
    def getNowDate: String = {
        val now: Date = new Date()
        val sdf: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS")
        sdf.format(now)
    }

    /**
     * 将yyyy-MM-dd HH:mm:ss格式时间转换为yyyyMMddHHmmss格式
     * @param dateString yyyy-MM-dd HH:mm:ss
     * @return yyyyMMddHHmmss
     */
    def getTransDateStr(dateString: String): String = {
        val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setTime(date)
        val sdf2: SimpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss")
        sdf2.format(date)
    }

    /**
     * 将计算两个时间相差的时间间隔,
     * 输入为 两个时间, 格式为: yyyy-MM-dd HH:mm:ss SSS
     * 输出Tuple, Tuple格式为(day, hour, min, sec)
     * @param dateStr 第一个时间
     * @param nextDateStr 第二个时间
     * @return
     */
    def diffTimes(dateStr: String, nextDateStr: String): (Long, Long, Long, Long) = {
        val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS")
        val cal = Calendar.getInstance()
        cal.setTime(sdf.parse(dateStr))
        val time1: Long = cal.getTimeInMillis
        cal.setTime(sdf.parse(nextDateStr))
        val time2: Long = cal.getTimeInMillis
        val diff = abs(time2 - time1)
        val day = diff / (24 * 60 * 60 * 1000)
        val hour = diff / (60 * 60 * 1000) - day * 24
        val min = (diff / (60 * 1000)) - day * 24 * 60 - hour * 60
        val sec = diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60
        val minutes: Long = (time2 - time1) / (1000 * 60)
        Integer.parseInt(String.valueOf(minutes))
        (day, hour, min, sec)
    }

    /**
     * 打印时间, 输入为 Tuple格式为(day, hour, min, sec)
     * @param triple (Long,Long,Long,Long)
     * @return
     */
    def diffTimesPrint(triple: (Long, Long, Long, Long)): String = {
        val str: Unit = triple match {
            case x if triple._1 != 0 => println(x._1 + " days " + x._2 + " hours " + x._3 + " minutes " + x._4 + " seconds")
            case x if triple._2 != 0 => println(x._2 + " hours " + x._3 + " minutes " + x._4 + " seconds")
            case x if triple._3 != 0 => println(x._3 + " minutes " + x._4 + " seconds")
            case _ => println(triple._4 + " seconds")
        }
        str.toString
    }

    /**
     * 获取两天之间的所有日期
     * @param beginDateStr 开始日期
     * @param endDateStr 结束日期
     * @param format 可选的参数, 日期格式
     * @return
     */
    def getDaysBetweenTwoDays(beginDateStr: String, endDateStr: String, format: String = "yyyyMMdd"): Array[String] = {
        val sdf = new SimpleDateFormat(format)
        val beginDate = sdf.parse(beginDateStr)
        val endDate = sdf.parse(endDateStr)
        val calendar = Calendar.getInstance()
        calendar.setTime(beginDate)
        val result = new ArrayBuffer[String]()
        while (calendar.getTime.compareTo(endDate) <= 0) {
            result += sdf.format(calendar.getTime)
            calendar.add(Calendar.DAY_OF_YEAR, 1)
        }
        result.toArray
    }


    /**
     * 获取当前周的第一天日期
     * @param dateString 当前日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getCurrentWeekBegin(dateString: String, format: String = "yyyyMMdd"): String = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setFirstDayOfWeek(Calendar.MONDAY)
        calendar.setTime(date)
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
        sdf.format(calendar.getTime)
    }

    /**
     * 获取当前周的所有日期
     * @param dateString 当前日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getCurrentWeekDays(dateString: String, format: String = "yyyyMMdd"): Array[String] = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setTime(date)
        val dayNum = calendar.get(Calendar.DAY_OF_WEEK)
        if (dayNum == 1) {
            val result = new Array[String](7)
            calendar.add(Calendar.DAY_OF_WEEK, -7)
            var i = 0
            while (i < result.length) {
                calendar.add(Calendar.DAY_OF_WEEK, 1)
                result(i) = sdf.format(calendar.getTime)
                i += 1
            }
            result
        } else {
            val result = new Array[String](dayNum - 1)
            calendar.add(Calendar.DAY_OF_WEEK, 1 - dayNum)
            var i = 0
            while (i < result.length) {
                calendar.add(Calendar.DAY_OF_WEEK, 1)
                result(i) = sdf.format(calendar.getTime)
                i += 1
            }
            result
        }
    }

    /**
     * 获取当前月的所有日期
     * @param dateString 当前日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getCurrentMonthDays(dateString: String, format: String = "yyyyMMdd"): Array[String] = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setTime(date)
        val dayNum = calendar.get(Calendar.DAY_OF_MONTH)
        val result = new Array[String](dayNum)
        calendar.add(Calendar.DAY_OF_MONTH, -dayNum)
        var i = 0
        while (i < result.length) {
            calendar.add(Calendar.DAY_OF_MONTH, 1)
            result(i) = sdf.format(calendar.getTime)
            i += 1
        }
        result
    }

    /**
     * 获取半年前的日期
     * @param dateStr 当前日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getDayBeforeHalfYear(dateStr: String, format: String = "yyyy-MM-dd"): String = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        calendar.add(Calendar.MONTH, -6)
        sdf.format(calendar.getTime)
    }

    /**
     * 获取一年前日期
     * @param dateStr 当前日期
     * @param format  可选的参数, 格式
     * @return
     */
    def getDayBeforeOneYear(dateStr: String, format: String = "yyyy-MM-dd"): String = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        calendar.add(Calendar.YEAR, -1)
        sdf.format(calendar.getTime)
    }

    /**
     * 判断某一天是否是周末
     * @param dateStr 日期
     * @param format 可选的参数, 格式
     * @return
     */
    def dayIsWeekend(dateStr: String, format: String = "yyyyMMdd"): Boolean = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY ||
            calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            true
        }else {
            false
        }
    }

    /**
     * 判断某一天是否是周日
     * @param dateStr 日期
     * @param format 可选的参数, 日期格式
     * @return
     */
    def dayIsWeekLast(dateStr: String, format: String = "yyyyMMdd"): Boolean = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            true
        }else {
            false
        }
    }

    /**
     * 获取指定日期当前月的最后一天
     * @param dateStr 指定日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getMonthMaxDay(dateStr: String, format: String = "yyyyMMdd"): Int = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        val MaxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
        MaxDay
    }

    /**
     * 获取一个月的第一天
     * @param dateStr 日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getFirstDayOfMonth(dateStr: String, format: String = "yyyyMMdd"): String = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 1)
        sdf.format(calendar.getTime)
    }

    /**
     * 返回月份的最后一天
     *
     * @param dateStr 日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getLastDayOfMonth(dateStr: String, format: String = "yyyyMMdd"): String = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 1)
        calendar.roll(Calendar.DATE, -1)
        sdf.format(calendar.getTime)
    }

    /**
     * 计算两天之间相差的天数
     * @param startDateStr 第一个日期
     * @param endDateStr 第二个日期
     * @param format 可选的参数, 格式
     * @return
     */
    def getDaysBetween(startDateStr: String, endDateStr: String, format: String = "yyyyMMdd"): Int = {
        val sdf = new SimpleDateFormat(format)
        val cal = Calendar.getInstance()
        cal.setTime(sdf.parse(startDateStr))
        val time1: Long = cal.getTimeInMillis
        cal.setTime(sdf.parse(endDateStr))
        val time2: Long = cal.getTimeInMillis
        val between_days: Long = (time2 - time1) / (1000 * 3600 * 24)
        Integer.parseInt(String.valueOf(between_days))
    }


    /**
     * 判断第一个日期是否小于等于第二个日期
     * @param firstDateStr 第一个日期
     * @param secondDateStr 第二个日期
     * @param format 可选的参数, 格式
     * @return
     */
    def compareDate(firstDateStr: String, secondDateStr: String, format: String = "yyyyMMdd"): Boolean = {
        val sdf = new SimpleDateFormat(format)
        val c1 = Calendar.getInstance()
        val c2 = Calendar.getInstance()
        c1.setTime(sdf.parse(firstDateStr))
        c2.setTime(sdf.parse(secondDateStr))
        if (c1.compareTo(c2) >= 0) {
            true
        }
        else {
            false
        }
    }

    /**
     * 判断日期字符串是否是符合格式的日期字符串
     * @param dateStr 日期字符串
     * @param format 可选的参数, 格式
     * @return
     */
    def isValidDate(dateStr: String, format: String = "yyyyMMdd"): Boolean = {
        val sdf = new SimpleDateFormat(format)
        var flag = true
        try {
            sdf.setLenient(false)
            sdf.parse(dateStr)
        } catch {
            case e: ParseException => e.printStackTrace()
                flag = false
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
        }
        flag
    }

    /**
     * 计算时间间隔, 单位天, 例如: ("20181010", "20201012") => 3
     * @param date1 日期1
     * @param date2 日期2
     * @param format 可选的参数, 格式
     * @return
     */
    def getDateSpace(date1: String, date2: String, format: String = "yyyyMMdd"): Long = {
        val sdf = new SimpleDateFormat(format)
        val d1 = (sdf.parse(date2).getTime - sdf.parse(date1).getTime) / 1000 / 3600 / 24 + 1
        d1
    }

    /**
     * 判断某一天日期是否是当前月最后一天
     * @param dateString 日期
     * @param format 可选的参数, 格式
     * @return
     */
    def isLastDayOfMonth(dateString: String, format: String = "yyyyMMdd"): Boolean = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.parse(dateString)
        val c = Calendar.getInstance()
        c.setTime(date)
        c.get(Calendar.DAY_OF_MONTH) == c.getActualMaximum(Calendar.DAY_OF_MONTH)
    }

    /**
     * 从时间戳获取为指定格式的日期
     * @param stamp 时间戳
     * @param format 可选的参数, 格式
     * @return
     */
    def getDateFromStamp(stamp: Long, format: String = "yyyyMMdd"): String = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.format(stamp)
        date
    }

    /**
     * 将时间戳转换为日期, 格式为yyyy-MM-dd HH:mm:ss SSS
     * @param stamp 时间戳
     * @return
     */
    def stampToDate(stamp: String): String = {
        try {
            if (stamp == null || stamp.trim.isEmpty) {
                return "-"
            }
            val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS")
            val lt = stamp.toLong
            val date = new Date(lt)
            //val date=classOf[Long].cast(stamp)
            sdf.format(date.getTime)
        } catch {
            case _: Exception => println("stamp" + ":" + stamp)
                "-"
        }
    }

    /**
     * 日期转时间戳
     * @param date 日期
     * @param format 时间格式
     * @return
     */
    def dateToStamp(date: String, format: String = "yyyy-MM-dd HH:mm:ss SSS"): String = {
        try {
            val sdf = new SimpleDateFormat(format)
            val time = sdf.parse(date).getTime
            time.toString
        } catch {
            case e: Exception => e.printStackTrace()
                "-"
        }
    }

    /**
     * 修正日期
     * @param date 日期 格式为 yyyyMMddHHmmssSSS
     * @param stamp 时间戳
     * @return 返回格式为 yyyyMMdd
     */
    def getFixStamp(date: String, stamp: Long): Long = {
        val sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS")
        val stampDate = sdf.format(stamp)
        val newDate = date + stampDate.substring(8)
        sdf.parse(newDate).getTime
    }

    /**
     * 获取当前小时(包含日期) yyyyMMddHH
     * @return
     */
    def getCurrentHour: String = {
        val sdf = new SimpleDateFormat("yyyyMMddHH")
        sdf.format(new Date())
    }

    /**
     * 返回两个小时之间的所有小时的列表
     * @param startHour 第一个小时
     * @param endHour 第二个小时
     * @return
     */
    def getHourList(startHour: String, endHour: String): List[String] = {
        val pattern = "HH"
        if (startHour.compareTo(endHour) < 0) {
            val start = DateTimeFormat.forPattern(pattern).parseDateTime(startHour)
                .plusHours(1).toString(pattern)
            startHour :: getHourList(start, endHour)
        } else {
            List(endHour)
        }
    }

    /**
     * 获取当前小时[HH]
     * @return
     */
    def getCurrentOnlyHour: String = {
        new DateTime().toString("HH")
    }

    /**
     * 获取两日期之前的小时差(不考虑分及分以下单位数值)
     * 格式精确到 yyyyMMddHH
     * @param date1 第一个日期
     * @param date2 第二个日期
     * @return
     */
    def getBetweenHour(date1: Date, date2: Date): Long = {
        val sdf = new SimpleDateFormat("yyyyMMddHH")
        sdf.format(date2).toLong - sdf.format(date1).toLong
    }

    /**
     * 获取两个日期之间的天数差
     * 格式精确到 yyyyMMdd
     * @param date1 第一个日期
     * @param date2 第二个日期
     * @return
     */
    def getBetweenDay(date1: Date, date2: Date, format: String = "yyyyMMdd"): Long = {
        val sdf = new SimpleDateFormat(format)
        sdf.format(date2).toLong - sdf.format(date1).toLong
    }

    /**
     * 获取今天剩余秒数
     * @return
     */
    def getTodayRemainSeconds: Int = {
        24 * 60 * 60 - new DateTime().getSecondOfDay
    }

    /**
     * 获取当前日期 yyyyMMdd
     * @return
     */
    def getToday(format: String = "yyyyMMdd"): String = {
        val sdf = new SimpleDateFormat(format)
        sdf.format(new Date())
    }

    /**
     * 获取两个日期的指定时间戳长度的分段间隔数量,默认按照自然天分隔,即计算两个日期之间相隔的天数
     * @param data1 第一个日期
     * @param date2 第二个日期
     * @param dateFormat 可选参数,日期格式,默认"yyyyMMdd"
     * @param timeStm 可选参数,时间戳,默认"86400000"(24*60*60*1000)
     * @return
     */
    def getDateDayDis(data1: String, date2: String, dateFormat: String = "yyyyMMdd", timeStm: Long = 86400000): Long = {
        //    timeStm  = 1000*3600*24
        val sdf = new SimpleDateFormat(dateFormat)
        val b = sdf.parse(data1).getTime - sdf.parse(date2).getTime
        val num = b / timeStm
        abs(num)
    }

    /**
     * 获取指定日期的下一个月的日期数组
     * @param dateString 指定日期
     * @param format 可选参数,格式,默认为 "yyyyMMdd"
     * @return
     */
    def getNextMonthDays(dateString: String, format: String = "yyyyMMdd"): Array[String] = {
        val sdf = new SimpleDateFormat(format)
        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setTime(date)

        calendar.add(Calendar.MONTH, 1)
        calendar.setTime(calendar.getTime)
        val dayNum = calendar.get(Calendar.DAY_OF_MONTH)
        val result = new Array[String](dayNum)
        calendar.add(Calendar.DAY_OF_MONTH, -dayNum)
        var i = 0
        while (i < result.length) {
            calendar.add(Calendar.DAY_OF_MONTH, 1)
            result(i) = sdf.format(calendar.getTime)
            i += 1
        }
        result
    }

    /**
     * 获取上个月的当前日期
     * @param dateString 当前日期
     * @param format 可选参数,格式,默认为 "yyyyMMdd"
     * @return 返回格式根据 format 决定, 若 format 不填, 则默认为 "yyyyMMdd"
     */
    def getLastMonthDay(dateString: String, format: String = "yyyyMMdd"): String = {
        val sdf = new SimpleDateFormat(format)

        val date = sdf.parse(dateString)
        val calendar = Calendar.getInstance()
        calendar.setTime(date)

        calendar.add(Calendar.MONTH, -1)
        calendar.setTime(calendar.getTime)
        sdf.format(calendar.getTime)
    }

    /**
     * 判断指定日期是周几
     * @param dateStr 指定日期
     * @param format 可选参数,格式,默认为 "yyyyMMdd"
     * @return
     */
    def dayInWeekIs(dateStr: String, format: String = "yyyyMMdd"): Int = {
        val sdf = new SimpleDateFormat(format)
        val calendar = Calendar.getInstance()
        calendar.setTime(sdf.parse(dateStr))
        val tmpWeekDay = calendar.get(Calendar.DAY_OF_WEEK)
        tmpWeekDay match {
            case 1 => 7
            case _ => tmpWeekDay - 1
        }
    }

    /*
    * 是否工作日
     */
    /**
     * 判断指定日期是否是工作日
     * @param dateStr 指定日期
     * @param format 可选参数,格式,默认为 "yyyyMMdd"
     * @return
     */
    def IsWorkDay(dateStr: String, format: String = "yyyyMMdd"): Boolean = {
        val dayOfWeek = dayInWeekIs(dateStr, format)
        dayOfWeek match {
            case a if a == 6 => false
            case a if a == 7 => false
            case _ => true
        }
    }

    /**
     * 将格式为 "yyyyMMdd" 的日期转换为 "yyyy年MM月dd日"
     * @param month 原始日期
     * @return
     */
    def monthToDesc(month: String): String = {
        val format = new java.text.SimpleDateFormat("yyyyMM")
        val dateArray = format.parse(month)
        val format2 = new java.text.SimpleDateFormat("yyyy年MM月")
        format2.format(dateArray)
    }

    /**
     * 将格式为 "yyyyMMddHHmmss" 的日期转换为 "yyyy年MM月dd日HH时mm分ss秒"
     * @param time 原始时间
     * @param timeFormat 原始时间格式，可选参数，默认为 yyyyMMddHHmmss
     * @param descFormat 输出时间格式，可选参数，默认为 yyyy年MM月dd日HH时mm分ss秒
     * @return
     */
    def timeToDesc(time: String, timeFormat: String = "yyyyMMddHHmmss", descFormat: String = "yyyy年MM月dd日HH时mm分ss秒"): String = {
        val format = new java.text.SimpleDateFormat(timeFormat)
        val dateArray = format.parse(time)
        val format2 = new java.text.SimpleDateFormat(descFormat)
        format2.format(dateArray)
    }

    /**
     * 获取指定时间后面多少分钟后的时间
     * @param time 时间
     * @param minutes 分钟数，若为负数，则表示之前的时间
     * @param timeFormat 时间格式, 可选
     * @return
     */
    def getTimeAfterMinutes(time: String, minutes: Int, timeFormat: String = "yyyyMMddHH"): String = {
        val format = new java.text.SimpleDateFormat(timeFormat)
        val oldTime = format.parse(time)
        val newTime = new Date(oldTime.getTime + minutes * 60 * 1000)
        format.format(newTime)
    }


    def main(args: Array[String]): Unit = {
        val date = getToday("yyyyMMddHH")
        println(date)
        println(getTimeAfterMinutes("2021051101", -60, "yyyyMMddHHmmss"))
    }

}
